package com.zoe.thread.th03_线程通信;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author Zoe
 * @Date: 2021/05/01
 * @Description https://www.bilibili.com/video/BV1vE411D7KE?p=43&vd_source=279fcae86988a7cf98f81a043336721c
 *         现在2个线程，可以操作初始值为0的一个变量，
 *         实现一个线程对变量+1，一个线程对该变量-1，
 *         实现交替，来10轮，变量初始值为0；
 *
 *         1: 高内聚低耦合的前提下/线程操作资源类
 *         2: 口诀：判断/干活/通知
 *         3: 多线程交互中,必须要防止多线程的虚假唤醒，也即（判断只用while 不能用if）
 *
 *         生产 消费
 */
class Cake {
    private int number = 0;

    private int incre = 0;
    private int decre = 0;

    private Lock lock = new ReentrantLock();

    public synchronized void increment() {
        // 1：判断 必须要用while；被唤醒之后要重新判断一次；参考生活中坐地铁的案列（扫码进站 -> 钥匙忘在家里，回家拿钥匙，再次进站的时候，需要二次安检）
        while (number != 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
        // 2：干活
        number++;
        incre++;
        // 3：通知
        notifyAll();
        System.out.println(incre+"  "+Thread.currentThread().getName() + " 生产了蛋糕" + number);
    }

    public synchronized void decrement() {
        // 1:判断
        while (number == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 2:干活
        number--;

        decre++;
        // 3:通知
        notifyAll();
        System.out.println(decre+"  "+Thread.currentThread().getName() + " 消费了蛋糕" + number);
    }
}

public class ThreadWaitNotifyDemoSync {
    public static void main(String[] args) {
        Cake cake = new Cake();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {

                cake.increment();
            }
        }, "厨师A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {

                cake.increment();
            }
        }, "厨师C").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {

                cake.decrement();
            }
        }, "消费B").start();



        new Thread(() -> {
            for (int i = 0; i < 10; i++) {

                cake.decrement();
            }
        }, "消费D").start();
    }
}
